`timescale 1ns / 1ps
/////////////////////////////////////////////////////////////////////////////
////                                                                     ////
//// Instituto Tecnologico de Costa Rica                                 ////
////                                                                     ////
//// Maquina estados finitos menor                                       ////
////                                                                     ////
//// Este archivo es parte del proyecto: Pong Game                       ////
//// http://repositorio-charmander.googlecode.com/svn/trunk/             ////
////                                                                     ////
//// Descripcion                                                         ////
//// Implementacion de un control de luces de semaforo como un proyecto  ////
//// del curso de Taller de Diseño Digital.                             ////
////                                                                     ////
//// Funcionamiento:                                                     ////
//// - Maquina de estados del juego de Pong. En este modulo es           ////
////   donde se procesan y se da la toma de decisiones por parte del     ////
////   programa para saber a que estado debera pasar segun las valores   ////
////   que ingresen.                                                     ////
////                                                                     ////
////                                                                     ////                                    
//// Autores:                                                            ////
//// - Gia Chen, kathya0812@gmail.com                                    ////
////   Edgar Rojas, edtec217@gmail.com                                   ////
////                                                                     ////
/////////////////////////////////////////////////////////////////////////////
module minor_FSM(_clk_i,_sync_rst_i,velocidad_i,mueve_fila_i,mueve_columna_i,inicia_i,
							paleta_i,perdio_o,inicia_fila_o, inicia_columna_o,posicion_bola_fila_o,
							posicion_bola_columna_o,velocidad_fila_o,velocidad_columna_o);
	 
	 //Entradas
	 input _clk_i;
    input _sync_rst_i;
    input inicia_i;
    input mueve_fila_i;
    input mueve_columna_i;
	 input [9:0] paleta_i;
	 input [3:0] velocidad_i;
	 
	 //Output
    output reg perdio_o;
    output reg inicia_fila_o;
    output reg inicia_columna_o;
    output reg [3:0] velocidad_fila_o;
    output reg [3:0] velocidad_columna_o;
    output reg [9:0] posicion_bola_fila_o;
    output reg [9:0] posicion_bola_columna_o;

	//Variables Temporales
	reg [2:0] estado_actual;
	reg indicador_incremento;
	reg sentido_fila_o;//0 positivo, 1 negativo
	reg sentido_columna_o;

	always @(posedge _clk_i)
	begin
		//Condicion que me indica si se hace un reset, en el caso de que 
		//se de un reset se vuelvo al estado 0.
		if (_sync_rst_i) 
			begin
				estado_actual <= 0;
			end
		else begin
			case (estado_actual)
				//Estado 0: Se inicializan las variables de salida.
				3'b000: 
					begin
						if (velocidad_i == 0) 
							begin 
								velocidad_fila_o <= 1;
								velocidad_columna_o <= 1;
							end
						else 
							begin 
								velocidad_fila_o <= velocidad_i; 
								velocidad_columna_o <= velocidad_i;
							end
						indicador_incremento <= 1;
						perdio_o <= 0;
						inicia_fila_o <= 0;
						inicia_columna_o <= 0;
						sentido_fila_o <= 0;
						sentido_columna_o <= 0;
						posicion_bola_fila_o <= 10'b0000101100;
						posicion_bola_columna_o <= 10'b0011011110;
						if (inicia_i == 1) begin	estado_actual <= 1; end
						else begin estado_actual <= 0; end
						
					end
				//Estado 1: Se encarga de mover la bola segun las se;ales de entrada.
				3'b001:  
					begin
						if (indicador_incremento) 
						begin
							indicador_incremento <= 0;  
							perdio_o <= 0;
							inicia_fila_o <= 1;
							inicia_columna_o <= 1;
							sentido_fila_o <= sentido_fila_o;
							sentido_columna_o <= sentido_columna_o;
							velocidad_fila_o <= velocidad_fila_o;
							velocidad_columna_o <= velocidad_columna_o;
							if (mueve_fila_i) 
								begin  
									if (sentido_fila_o) begin posicion_bola_fila_o <= posicion_bola_fila_o -1;	end
									else begin posicion_bola_fila_o <= posicion_bola_fila_o +1 ; end
								end
							if (mueve_columna_i)
								begin  
									if (sentido_columna_o) begin posicion_bola_columna_o <= posicion_bola_columna_o -1;	end
									else begin posicion_bola_columna_o <= posicion_bola_columna_o +1; end
								end
							
						end
						estado_actual <= 2;
					end
				//Estado 1: Estado que reinician los contadores de inicia_fila_o o inicia_columna_o segun sea el estado.
				3'b010:  
					begin
						indicador_incremento <= 1;
						perdio_o <= 0;
						if (mueve_fila_i) begin inicia_fila_o <= 0; end
						else begin inicia_fila_o <= inicia_fila_o; end
						if (mueve_columna_i) begin inicia_columna_o <= 0; end
						else begin inicia_columna_o <= inicia_columna_o; end
						sentido_fila_o <= sentido_fila_o;
						sentido_columna_o <= sentido_columna_o;
						velocidad_fila_o <= velocidad_fila_o;
						velocidad_columna_o <= velocidad_columna_o;
						posicion_bola_fila_o <= posicion_bola_fila_o;
						posicion_bola_columna_o <= posicion_bola_columna_o;
						estado_actual <= 3;
					end
				//Estado 3: estado que se encarga direccionar la bola segun los casos de colisiones.
				3'b011: 
					begin
						perdio_o <= 0;
						inicia_fila_o <= 1;
						inicia_columna_o <= 1;	
						if (posicion_bola_columna_o == 10'b0111001111) sentido_columna_o <= 1; // colision con pared superior	
						if (posicion_bola_fila_o == 10'b1001101111) sentido_fila_o <= 1; // colision con pared derecha						
						if (posicion_bola_columna_o == 10'b0000001000) sentido_columna_o <= 0; // colision con pared inferior
						if (posicion_bola_fila_o == 10'b0000100100) begin
						
							if (posicion_bola_columna_o < (paleta_i+8) & posicion_bola_columna_o >= paleta_i-7) begin 
								posicion_bola_fila_o <= posicion_bola_fila_o + 1;
								sentido_fila_o <= 0;
								velocidad_fila_o <= velocidad_fila_o;
								if (velocidad_columna_o >= 13) begin velocidad_columna_o <= 15; end
								else begin velocidad_columna_o <= velocidad_columna_o + 3;  end
							end
							
							else if (posicion_bola_columna_o < (paleta_i+16) & posicion_bola_columna_o >= (paleta_i+8)) begin 
								posicion_bola_fila_o <= posicion_bola_fila_o + 1;
								sentido_fila_o <= 0;
								if (velocidad_fila_o == 15) begin velocidad_fila_o <= 15; end
								else begin velocidad_fila_o <= velocidad_fila_o + 1;  end
								if (velocidad_columna_o >= 14) begin velocidad_columna_o <= 15; end
								else begin velocidad_columna_o <= velocidad_columna_o + 2;  end
							end
							
							else if (posicion_bola_columna_o < (paleta_i+24) &  posicion_bola_columna_o >= (paleta_i+16)) begin 
								posicion_bola_fila_o <= posicion_bola_fila_o + 1;
								sentido_fila_o <= 0;
								if (velocidad_fila_o >= 14) begin velocidad_fila_o <= 15; end
								else begin velocidad_fila_o <= velocidad_fila_o + 2;  end
								if (velocidad_columna_o == 15) begin velocidad_columna_o <= 15; end
								else begin velocidad_columna_o <= velocidad_columna_o + 1;  end
							end
							
							else if (posicion_bola_columna_o < (paleta_i+40) & posicion_bola_columna_o >= (paleta_i+24)) begin 
								posicion_bola_fila_o <= posicion_bola_fila_o + 1;
								sentido_fila_o <= 0;
								if (velocidad_fila_o >= 13) begin velocidad_fila_o <= 15; end
								else begin velocidad_fila_o <= velocidad_fila_o + 3;  end
								velocidad_columna_o <= velocidad_columna_o;
							end
							
							else if (posicion_bola_columna_o < (paleta_i+48) & posicion_bola_columna_o >= (paleta_i+40)) begin 
								posicion_bola_fila_o <= posicion_bola_fila_o + 1;
								sentido_fila_o <= 0;
								if (velocidad_fila_o >= 14) begin velocidad_fila_o <= 15; end
								else begin velocidad_fila_o <= velocidad_fila_o + 2;  end
								if (velocidad_columna_o == 1) begin velocidad_columna_o <= 1; end
								else begin velocidad_columna_o <= velocidad_columna_o - 1;  end
							end
							
							else if (posicion_bola_columna_o < (paleta_i+56) & posicion_bola_columna_o >= (paleta_i+48)) begin 
								posicion_bola_fila_o <= posicion_bola_fila_o + 1;
								sentido_fila_o <= 0;
								if (velocidad_fila_o == 15) begin velocidad_fila_o <= 15; end
								else begin velocidad_fila_o <= velocidad_fila_o + 1;  end
								if (velocidad_columna_o <= 2) begin velocidad_columna_o <= 1; end
								else begin velocidad_columna_o <= velocidad_columna_o - 2;  end
							end
							
							else if (posicion_bola_columna_o < (paleta_i+64) & posicion_bola_columna_o >= (paleta_i+56)) begin 
								posicion_bola_fila_o <= posicion_bola_fila_o + 1;
								sentido_fila_o  <= 0;
								velocidad_fila_o  <= velocidad_fila_o ;
								if (velocidad_columna_o <= 3) begin velocidad_columna_o <= 1; end
								else begin velocidad_columna_o <= velocidad_columna_o - 3;  end
							end
						end
						if (posicion_bola_fila_o == 0) begin estado_actual <= 4; end
						else 
							begin
								if (mueve_fila_i || mueve_columna_i) begin estado_actual <= 1; end
								else begin estado_actual <= 3; end
							end
					end
				//Estado 4: Fin del juego, este estado se encarga de detener el movimiento de la bola. 
				//Ademas le manda la se;al a la FSM mayor e indicarle que el juego ya termino.
				3'b100: 
					begin
						perdio_o <= 1;
						inicia_fila_o <= 0;
						inicia_columna_o <= 0;
						sentido_fila_o <= sentido_fila_o;
						sentido_columna_o <= sentido_columna_o;
						velocidad_fila_o <= velocidad_fila_o;
						velocidad_columna_o <= velocidad_columna_o;
						posicion_bola_fila_o <= posicion_bola_fila_o;
						posicion_bola_columna_o <= posicion_bola_columna_o;
						estado_actual <= 4;
					end
			endcase
		end
	end//end always

endmodule
